<template>
<!--  //给模版添加 ref属性-->
  <div class="dropdown" ref="dropdownRef">
    <!-- 接受外界传入的用户名字 -->
    <a
      href="#"
      class="btn btn-outline-light my-2 dropdown-toggle"
      @click.prevent="toggleOpen"
      >{{ title }}</a
    >
    <!-- 不点击默认显示 并且display 默认在框架中默认display:none    vue 通过v-if 控制其元素的  -->
    <ul class="dropdown-menu" :style="{ display: 'block' }" v-if="isOpen">
      <!--      <li class="dropdown-item"><a href="#">新建文章</a></li>
            <li class="dropdown-item"><a href="#">编辑资料</a></li>-->
      <slot></slot>
    </ul>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, watch } from "vue";
import useClickOutside from "@/hooks/useClickOutside";

export default defineComponent({
  props: {
    title: {
      type: String,
      required: true,
    },
  },
  setup() {
    const isOpen = ref(false);
    /*
     // 通过给标签绑定的 ref 获取 DOM结点；
      dom节点设置类型，应该使用 联合类型，因为 下拉组件可能存在，即 HTMLElement 类型，可能不存在，即 null 类型

      第一个null是类型的一部分（在尖括号<>之间定义）。

    这意味着这个ref（）的值可以是HTMLElement元素，也可以是null。

      第二个空值是最初设置的ref的值。
    dropdownRef是一个ref，可以是HTMLElement，也可以是null，当前为null。



    ts 泛型
    // 使用泛型来创建一个函数：

// 使用泛型来创建一个函数：

function id<Type>(value: Type): Type {
  return value
}

// 调用泛型函数：

// 1 以 number 类型调用泛型函数
const num = id<number | string >("10")
console.log(num);
    */
    //在逻辑中，通过与 ref属性 相同的命名，获取对应 dom元素
    //注意，dom节点设置类型，应该使用 联合类型，因为 下拉组件可能存在，即 HTMLElement 类型，可能不存在，即 null 类型
    const dropdownRef = ref<null | HTMLElement>(null);

    /*
    点击 ”你好，xxx“ 的按钮，可以实现下拉菜单的显示与隐藏，也就是说给按钮绑定点击事件，切换 isOpen 值，即可实现 菜单展开折叠的效果
dropdown-menu 在 bootstrap中默认为 display:none，在 GlobalHeader.vue 中是通过 v-if 判断是否显示的，因此，此处要修改为 display:block，通过变量 isOpen 决定菜单是否显示

    */
    const toggleOpen = () => {
      isOpen.value = !isOpen.value;
    };
    // 点击边框外部隐藏下拉框的回调函数
    /*const handler = (e: MouseEvent) => {

      if (dropdownRef.value) {
        这层判断必须有，dropdownRef.value 可能是null 而null是没有contains方法的
        没有此层 if 判断 if 内部 dropdownRef.value.contains 会报错

        contains 方法 ：
节点的方法 检测点击的地方是否包含在调用方法的节点中   在这里e.target 挂在了doc上 是doc的点击事件
：在js中只能判断一个dom元素中是否包含某个dom元素，返回布尔值。

        if (!dropdownRef.value.contains(e.target as HTMLElement) && isOpen.value) {
          isOpen.value = false
        }
      }
   // 生命周期 挂载点击事件
     onMounted(() => {
       document.addEventListener("click", handler);
     });
    // 生命周期，卸载点击事件
     onUnmounted(() => {
       document.removeEventListener("click", handler);
     });


    }*/


    /*
      返回值true 点的 其他地方
      返回false  点的组件

    */

    const isClickOutside = useClickOutside(dropdownRef);
    watch(isClickOutside, () => {
      if (isOpen.value && isClickOutside.value) {
        isOpen.value = false;
      }
    });
    return {
      // 模板中使用弹出去
      isOpen,
      toggleOpen,
      //将 setup() 中的 dropdownRef return 出去，返回和 ref 同名的响应式对象，就可以拿到对应的 DOM节点
      dropdownRef,
    };
  },
});
</script>

<style scoped>
</style>
